/*
* Copyright 2010 Competentum group
*
* Licensed under the GNU General Public License, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.gnu.org/licenses/gpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.competentum.data.parser
{
	import com.competentum.builders.BindsBuilder;
	import com.competentum.builders.DataBuildersFactory;
	import com.competentum.builders.EmployeesBuilder;
	import com.competentum.builders.PreferencesBuilder;
	import com.competentum.builders.ProjectsBuilder;
	import com.competentum.vos.AbstractItemVO;
	import com.competentum.vos.BindVO;
	import com.competentum.windows.Scope;
	import com.competentum.windows.ScopesManager;
	import com.competentum.lib.data.builders.AbstractDataBuilder;
	import com.competentum.lib.parser.IDataParser;
	
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	import mx.controls.Alert;
	
	/**
	 * Parser config xml.
	 * Parses data into dataBuilders.
	 * 
	 * !!! Warning !!!
	 * On updating tool update version number at PreferencesBuilder.VERSION.
	 * This constant is used for compatibility checking of loaded xml files.	 *
	 *  
	 * @author Valentine Abanosimov
	 * */
	public class XMLParser extends EventDispatcher implements IDataParser
	{
		public function XMLParser(target:IEventDispatcher=null)
		{
			super(target);
		}
		
		public function parse(data:String, scope:*):void
		{
			var xml:XML = new XML(data);
			var employees:XMLList = xml.employees.employee;
			var projects:XMLList = xml.projects.project;
			var binds:XMLList = xml.binds.bind;
			var metadata:XML = xml.metadata[0];
			if (metadata)
			{
				var appVersion:String = (DataBuildersFactory.getDataBuilder(PreferencesBuilder.TYPE, scope) as PreferencesBuilder).VERSION;
				var fileVersion:String = metadata.@version;
				if (fileVersion != null && fileVersion != '')
				{
					if (oldAppVersion(appVersion, fileVersion))
					{
						Alert.show('You use outdated version of application: ' + appVersion + '.\nFile that you try to open was created in ' + fileVersion + ' build.\nUsing of this version can lead to unexpected data handling and loss.\nWe recommend you to update the tool', 'Warning! Old app version ' + appVersion, 4,
							ScopesManager.currentWindow);
					}
				}
			}
			
			var vo:AbstractItemVO;
			var i:uint = 0;
			
			//reinitialize data provider but do not kill reference because binding die - just removeAll
			var projectsBuilder:ProjectsBuilder = DataBuildersFactory.getDataBuilder(ProjectsBuilder.TYPE, scope) as ProjectsBuilder;
			var employeesBuilder:EmployeesBuilder = DataBuildersFactory.getDataBuilder(EmployeesBuilder.TYPE, scope) as EmployeesBuilder;
			var bindsBuilder:BindsBuilder = DataBuildersFactory.getDataBuilder(BindsBuilder.TYPE, scope) as BindsBuilder;
			
			projectsBuilder.removeAllItems();
			for ( i = 0; i < projects.length(); i++)
			{
				vo = projectsBuilder.createItemFromXML(projects[i]);
			}
			
			employeesBuilder.removeAllItems();
			bindsBuilder.removeAllItems();
			for ( i = 0; i < employees.length(); i++)
			{
				vo = employeesBuilder.createItemFromXML(employees[i]);
				// old format
				if ((employees[i].bind as XMLList).length() > 0)
				{
					var bindsList:XMLList = employees[i].bind;
					for (var bindIndex:int = 0; bindIndex < bindsList.length(); bindIndex ++ )
					{
						var bind:XML = bindsList[bindIndex];
						bindsBuilder.createItem(vo, projectsBuilder.getItemByUid(bind.@toProject) as AbstractItemVO, bind.@hoursReserved);
					}
				}
			}
			
			/*
			// new format that fits new data model
			// as yet doesn't used for the sake of maximum compatibility with previous versions
			for ( i = 0; i < binds.length(); i++)
			{
				vo = bindsBuilder.createItemFromXML(binds[i]);
			}
			*/
		}
		
		public function export(scope:*):String
		{
			return getDeserializeConfig(scope).toXMLString();
		}
		
		/**
		 * Used by HistoryChangesManager to check whether an action had changed model and it really needs to be saved in history
		 * */
		public static function getDeserializeConfig(scope:Scope):XML
		{
			var configXML:XML = 
				<root>
					<metadata>
					</metadata>
					<employees>
					</employees>
					<projects>
					</projects>
				</root>;
			
			configXML.metadata[0].@version = (DataBuildersFactory.getDataBuilder(PreferencesBuilder.TYPE, scope) as PreferencesBuilder).VERSION;
			
			var i:uint = 0;
			var vo:AbstractItemVO;
			//export employees list
			//export binds list for old format
			// I decided to keep format unchanged even though it doesn't fit new data model
			var employeeBuilder:AbstractDataBuilder = DataBuildersFactory.getDataBuilder(EmployeesBuilder.TYPE, scope);
			var bindsBuilder:AbstractDataBuilder = DataBuildersFactory.getDataBuilder(BindsBuilder.TYPE, scope);
			for (i = 0 ; i < employeeBuilder.itemsVector.length ; i ++ )
			{
				vo = employeeBuilder.itemsVector[i] as AbstractItemVO;
				if (vo)
				{
					var employeeXML:XML = vo.exportToXML();
					var binds:Vector.<BindVO> = (bindsBuilder as BindsBuilder).getBindingsListForItem(vo);
					for (var bindIndex:int = 0; bindIndex < binds.length; bindIndex ++ )
					{
						employeeXML.appendChild(binds[bindIndex].exportToXML());
					}
					configXML.employees.appendChild(employeeXML);
				}
			}
			//export projects list
			var projectBuilder:AbstractDataBuilder = DataBuildersFactory.getDataBuilder(ProjectsBuilder.TYPE, scope);
			for ( i = 0 ; i < projectBuilder.itemsVector.length ; i ++ )
			{
				vo = projectBuilder.itemsVector[i] as AbstractItemVO;
				if (vo)
				{
					configXML.projects.appendChild(vo.exportToXML());
				}
			}
			//export binds list for new format
			/*for ( i = 0 ; i < bindsBuilder.itemsVector.length ; i ++ ) {
				vo = bindsBuilder.itemsVector[i] as AbstractItemVO;
				if ( vo ) {
					configXML.binds.appendChild( vo.exportToXML() );
				}
			}*/
			
			return configXML; 
		}
		
		private function toBoolean(string:String):Boolean
		{
			return string == 'true';
		}
		
		/**
		 * Returns true if app version is too old comparing with file version
		 * */
		private function oldAppVersion(appVersion:String, fileVersion:String):Boolean
		{
			var appV:Array = appVersion.split('.');
			var fileV:Array = fileVersion.split('.');
			var i:int;
			var diff:int = appV.length - fileV.length;
			for (i = 0; i < diff; i ++ )
			{
				fileV.push('0');
			}
			for (i = 0; i < -diff; i ++ )
			{
				appV.push('0');
			}
			for (i = 0; i < appV.length; i ++ )
			{
				appV[i] = int(appV[i]);
				if (int(appV[i]) < int(fileV[i]))
					return true;
				if (int(appV[i]) > int(fileV[i]))
					return false;
			}
			return false;
		}
	}
}